/*
 * Copyright (C) Francisco Morero Peyrona. All rights reserved.
 *
 * This software is published under the terms of Open Source
 * License version 1.1, a copy of which has been included with this
 * distribution in the License.txt file.
 */

package jdbcmanager.dbtools.tableditor;

import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;

import jdbcmanager.app.*;
import jdbcmanager.dbtools.*;
import jdbcmanager.dbtools.datatypes.*;


/**
 * A JTable to show a "DB Table Structure".
 * It also has functionality to add, remove, edit and shift fields.
 *
 * @author Francisco Morero Peyrona
 */
final class JxTableColumns extends JxTableParent
{
   // Column positions in table
   private final static int nKEY  = 0;
   private final static int nNAME = 1;
   private final static int nTYPE = 2;
   private final static int nSIZE = 3;   // Size or number of digist before decimal separator
   private final static int nSCAL = 4;   // Scale: number of digits after decimal separator
   private final static int nNULL = 5;   // Is nullable?
   private final static int nAUTO = 6;   // Is autoincrement?
   private final static int nDEFA = 7;   // Default value
   
   private TableColumnTypeDefinition[] aoTypeDef;

   //-------------------------------------------------------------------------//

   JxTableColumns()
   {
      this( null );
   }

   JxTableColumns( TableColumnDefinition[] aColumn )
   {
      setModel( new ColumnTableModel() );
      setHead( new String[] { "", "Field Name", "Type Name", "Size", "Dec", "Nullable", "AutoInc", "Default" } );
      setColumns( aColumn );
      init();
   }
   
   void setColumns( TableColumnDefinition[] aColumn )
   {
      setData( aColumn );
      
      if( getRowCount() == 0 )
         addRow();
   }

   TableColumnDefinition[] getColumns()
   {
      TableColumnDefinition[] aRet = new TableColumnDefinition[ this.vData.size() ];

      this.vData.copyInto( aRet );

      return aRet;
   }

   /**
    * @see jdbcmanager.dbtools.tableditor.JxTableParent#createEmptyRow()
    */
   protected Object createEmptyRow()
   {
      return new TableColumnDefinition();
   }
   
   //-------------------------------------------------------------------------//

   private void init()
   {
      this.aoTypeDef = DbUtil.getAgentDBMS().getAgentMetaData().getSupportedColumnTypes();
      
      // Sets PK column icon
      TableCellRenderer hr = new DefaultTableCellRenderer();
      ((JLabel) hr).setIcon( App.getIcon( getClass(), "key" ) );
      (getColumnModel().getColumn( nKEY )).setHeaderRenderer( hr );
      
      // Sets cell renderer for PRIMARY KEY column
      (getColumnModel().getColumn( nKEY )).setCellRenderer( new KeyColumnCellRenderer() );
      
      // Sets ComboBox to edit field types -----------------
      String[] asName = new String[ aoTypeDef.length ];
      
      for( int n = 0; n < asName.length; n++ )
         asName[n] = this.aoTypeDef[n].getName();
      
      JComboBox cmb = new JComboBox( asName );
                cmb.setSelectedIndex( 0 );
                
      (getColumnModel().getColumn( nTYPE )).setCellEditor( new DefaultCellEditor( cmb ) );
                  
      // Sets renderer for columns that can be enabled or disabled
      SizeAndScaleColumnCellRenderer sasccr = new SizeAndScaleColumnCellRenderer();
       
      (getColumnModel().getColumn( nSIZE )).setCellRenderer( sasccr );
      (getColumnModel().getColumn( nSCAL )).setCellRenderer( sasccr );
      
      NullAndAutoColumnsCellRenderer naaccr = new NullAndAutoColumnsCellRenderer();
      
      (getColumnModel().getColumn( nNULL )).setCellRenderer( naaccr );
      (getColumnModel().getColumn( nAUTO )).setCellRenderer( naaccr );
      //----------------------------------------------------

      getColumnModel().getColumn( nKEY  ).setPreferredWidth(  18 );
      getColumnModel().getColumn( nNAME ).setPreferredWidth(  88 );
      getColumnModel().getColumn( nTYPE ).setPreferredWidth( 109 );
      getColumnModel().getColumn( nSIZE ).setPreferredWidth(  40 );
      getColumnModel().getColumn( nSCAL ).setPreferredWidth(  28 );
      getColumnModel().getColumn( nNULL ).setPreferredWidth(  45 );
      getColumnModel().getColumn( nAUTO ).setPreferredWidth(  45 );
      getColumnModel().getColumn( nDEFA ).setPreferredWidth(  65 );
   }

   //---------------------------------------------------------------//
   // INNER CLASS: TABLE MODEL
   //---------------------------------------------------------------//
   private final class ColumnTableModel extends JxTableParent.ParentTableModel
   {
      public Object getValueAt( int nRow, int nCol )
      {
         TableColumnDefinition column = (TableColumnDefinition) JxTableColumns.this.vData.get( nRow );
         Object oRet;

         switch( nCol )
         {
            case nKEY : oRet = new Boolean( column.isPrimaryKey() );    break;
            case nNAME: oRet = column.getName();                        break;
            case nTYPE: oRet = column.getType().getName();              break;
            case nSIZE: oRet = new Integer( column.getSize() );         break;
            case nSCAL: oRet = new Integer( column.getScale() );        break;
            case nNULL: oRet = new Boolean( column.isNullable() );      break;
            case nAUTO: oRet = new Boolean( column.isAutoIncrement() ); break;
            case nDEFA: oRet = column.getDefaultValue();                break;
            default:    oRet = "<Error>";  // Avoid to create this String instance if there is no error
         }

         return oRet;
      }

      public void setValueAt( Object value, int nRow, int nCol )
      {
         TableColumnDefinition column = (TableColumnDefinition) JxTableColumns.this.vData.get( nRow );

         switch( nCol )
         {
            case nKEY : column.setPrimaryKey( ((Boolean) value).booleanValue() );    break;
            case nNAME: column.setName( (String) value );                            break;
            case nTYPE: column.setType( name2Type( (String) value ) );               break;
            case nSIZE: column.setSize( ((Integer) value).intValue() );              break;
            case nSCAL: column.setScale( ((Integer) value).intValue() );             break;
            case nNULL: column.setNullable( ((Boolean) value).booleanValue() );      break;
            case nAUTO: column.setAutoIncrement( ((Boolean) value).booleanValue() ); break;
            case nDEFA: column.setDefaultValue( value );                             break;
         }
      }
      
      private TableColumnTypeDefinition name2Type( String sTypeName )
      {
         int nIndex = TableColumnTypeDefinition.searchOnName( JxTableColumns.this.aoTypeDef, sTypeName );
         
         return JxTableColumns.this.aoTypeDef[ nIndex ];
      }
   }
   
   //-------------------------------------------------------------------------//
   // INNER CLASS: Shows a combo box to renderize the column cells
   //-------------------------------------------------------------------------//
   private final class KeyColumnCellRenderer extends JCheckBox implements TableCellRenderer 
   {
      KeyColumnCellRenderer()
      {
         setHorizontalAlignment( SwingConstants.CENTER );
      }

      public Component getTableCellRendererComponent( JTable table, Object value, boolean bSelected, boolean bHasFocus, int nRow, int nCol )
      {
         TableColumnDefinition column = (TableColumnDefinition) JxTableColumns.this.vData.get( nRow );
         
         setSelected( ((Boolean) value).booleanValue() );
         setBackground( (bSelected) ? JxTableColumns.this.getSelectionBackground() : JxTableColumns.this.getBackground() );
         
         if( isSelected() )
         {
            column.setNullable( false );  // A PK can't be nullable
            ((AbstractTableModel) table.getModel()).fireTableRowsUpdated( nRow, nRow );
         }
         
         return this;
      }      
   }
   
   //-------------------------------------------------------------------------//
   // INNER CLASS: to show cells enabled or disabled 
   //-------------------------------------------------------------------------//
   private final class SizeAndScaleColumnCellRenderer extends DefaultTableCellRenderer
   {
      SizeAndScaleColumnCellRenderer()
      {
         setHorizontalAlignment( SwingConstants.RIGHT );
      }
       
      public Component getTableCellRendererComponent( JTable table, Object value, boolean bSelected, boolean bHasFocus, int nRow, int nCol )
      {
         boolean               bEnabled  = true;
         Component             component = super.getTableCellRendererComponent( table, value, bSelected, bHasFocus, nRow, nCol );
         TableColumnDefinition column    = (TableColumnDefinition) JxTableColumns.this.vData.get( nRow );
         
         if( nCol == nSIZE )
           bEnabled = DbUtil.getAgentDBMS().getAgentSQL().isVariableLengthType( column.getType() );
         else if( nCol == nSCAL )
           bEnabled = false;  // This can be enabled in the future if there is some DBMS that allows to specify the decimal part --> bEnabled && (column.getType().getMaxScale() > 0);
         
         component.setEnabled( bEnabled );
         
         return component;
      }
   }
   
   //-------------------------------------------------------------------------//
   // INNER CLASS: to show check boxes enabled or disabled 
   //-------------------------------------------------------------------------//
   private final class NullAndAutoColumnsCellRenderer extends JCheckBox implements TableCellRenderer
   {
      NullAndAutoColumnsCellRenderer()
      {
         setHorizontalAlignment( SwingConstants.CENTER );
      }
      
      public Component getTableCellRendererComponent( JTable table, Object value, boolean bSelected, boolean bHasFocus, int nRow, int nCol )
      {
         boolean bEnabled = true;
         TableColumnDefinition column = (TableColumnDefinition) JxTableColumns.this.vData.get( nRow );
         
         if( nCol == nNULL )
            bEnabled = column.getType().isNullabe() && (! column.isPrimaryKey());  // PK can't be nullable
         else if( nCol == nAUTO )
            bEnabled = column.getType().isAutoIncrementable();
         
         setSelected( ((Boolean) value).booleanValue() );
         setEnabled( bEnabled );
         setBackground( (bSelected) ? JxTableColumns.this.getSelectionBackground() : JxTableColumns.this.getBackground() );
         
         return this;
      }
   }
}